C言語メモ
■ | typedef とdefineの違い | |||||||||||||||||||||||||||||||||||
typedefは新しいデータ型の名前(別名)を作成するものです。 (例) typedef int myINT は、 myINTと云う同義語をつくり その意味は intです。 すなわち myINT a; は int a; と同等に扱われます。 一方、 #define myINT int も myINT a; は int a; と同等に扱われます。 しかし myINT a,b; はエラーとなる。 コンパイラは int a; は理解するが bに関しては解釈不能となる。 ★★ #defineはプリプロセッサにより解釈され、typedefはコンパイラが解釈する。 |
||||||||||||||||||||||||||||||||||||
■ | typedef による定義 | |||||||||||||||||||||||||||||||||||
■ 予約語 typedefの意味 typedef int myINT; と書くと myINTは intの別名(エイリアス)となり myINT i = 7, j = 8, k = 9; i, j, kは それぞれ7,8,9の整数である。 |
||||||||||||||||||||||||||||||||||||
したがって、![]() は、正確に表現すると、『型名 struct RECA{ int x; int y}の構造体の別名型が RECAであることを定義』している。 上記の定義に於いては構造体のタグ名RECAと別名RECAが同じであるが、定義に於いてタグ名と別名が異なっても またタグ名が無くてもよい。 プログラムの実行結果に差異はない。 タグ名は無効であり、使えない。 以下、参照 |
||||||||||||||||||||||||||||||||||||
#include <stdio.h> //構造体タグ名RECAは、別名の型名RECAと同じ場合 typedef struct RECA //タグ名 { int x; int y; } RECA; //型名 //構造体タグ名なしの場合 typedef struct { int x; int y; } RECB; //型名 //構造体タグ名と別名の型名は異なる場合 typedef struct XYZ //タグ名 //→ タグ名 XYZはプログラムの中では無効であり、使えない。 { int x; int y; } RECC; //型名 int main() { RECA reca; //RECA reca;が無いとreca.x = 1;reca.y = 2;がコンパラエラーとなる reca.x = 1; reca.y = 2; RECB recb; recb.x = 3; recb.y = 4; RECC recc; recc.x = 5; recc.y = 6; // XYX xyz; //XYZ xyz;はコンパイラエラーとなる printf("reca.x=%d, reca.y=%d\n",reca.x, reca.y); printf("recb.x=%d, recb.y=%d\n",recb.x,recb.y); printf("recc.x=%d, recc.y=%d\n",recc.x,recc.y); return 0; } |
||||||||||||||||||||||||||||||||||||
<実行結果> | ||||||||||||||||||||||||||||||||||||
reca.x=1, reca.y=2 recb.x=3, recb.y=4 recc.x=5, recc.y=6 |
||||||||||||||||||||||||||||||||||||
(参考使用例:Harmony gfx_driver.h) → URL | ||||||||||||||||||||||||||||||||||||
■ 構造体の定義に typedef を使うメリット | ||||||||||||||||||||||||||||||||||||
1. 構造体を宣言する時(オブジェクトを生成する時) struct を書く手間が省ける。 2. ソースコードの可読性が向上する。 3. オブジェクト指向的なソースコードをつくることができる |
||||||||||||||||||||||||||||||||||||
<typedefを使用した場合> | ||||||||||||||||||||||||||||||||||||
//Harmony app.h より typedef struct //構造体を定義 { /* The application's current state */ APP_STATES state; /* TODO: Define any additional data used by the application. */ } APP_DATA; APP_DATA appData; //構造体を宣言、オブジェクトを生成 | ||||||||||||||||||||||||||||||||||||
<typedefを使用しない場合> | ||||||||||||||||||||||||||||||||||||
struct //構造体を定義 { /* The application's current state */ APP_STATES state; /* TODO: Define any additional data used by the application. */ } APP_DATA; struct APP_DATA appData; //構造体を宣言、オブジェクトを生成 |
||||||||||||||||||||||||||||||||||||
■ C++、Javaのクラスとの記述比較 | ||||||||||||||||||||||||||||||||||||
Cでtypedef を使った記述をすることにより、C++やJavaのようなオブジェクト指向的なコードを書くことができるようになる。 | ||||||||||||||||||||||||||||||||||||
1. Cのtypedefを使った記述 | ||||||||||||||||||||||||||||||||||||
#include<stdio.h> typedef struct { int x; int y; }REC; int main() { REC rec; rec.x = 1; rec.y = 2; printf("rec.x=%d\n", rec.x); printf("rec.y=%d", rec.y); } |
||||||||||||||||||||||||||||||||||||
<実行結果> | ||||||||||||||||||||||||||||||||||||
rec.x=1 rec.y=2 |
||||||||||||||||||||||||||||||||||||
2. C++のクラスを使った記述 | ||||||||||||||||||||||||||||||||||||
#include<iostream> using namespace std; class REC{ public: int x; int y; }; int main() { REC rec; rec.x = 1; rec.y = 2; cout<<"rec.x = "<<rec.x<<endl; cout<<"rec.y = "<<rec.y<<endl; return 0; } |
||||||||||||||||||||||||||||||||||||
<実行結果> | ||||||||||||||||||||||||||||||||||||
rec.x = 1 rec.y = 2 |
||||||||||||||||||||||||||||||||||||
3. Javaのクラスを使った記述 | ||||||||||||||||||||||||||||||||||||
class REC{ int x; int y; } public class Java_Variable_xy { public static void main(String[] args) { REC rec = new REC(); rec.x = 1; rec.y = 2; System.out.println("rec.x = " + rec.x ); System.out.println("rec.y = " + rec.y ); } } |
||||||||||||||||||||||||||||||||||||
<実行結果> | ||||||||||||||||||||||||||||||||||||
rec.x = 1 rec.y = 2 |
||||||||||||||||||||||||||||||||||||
■ typedef enum | ||||||||||||||||||||||||||||||||||||
C言語でオブジェクト指向のプログラミングをする場合、 構造体と同様に、『名前付き整数定数に typedef enum を用いて列挙型の別名を定義する』 ことが行われる。![]() 『列挙型 { APP_STATE_INIT=0,APP_STATE_DISK_SCANNING,APP_STATE_OPEN_FILE,APP_STATE_SEND_DATA,}の別名型が APP_STATES であることを定義』している。 以下、参照 |
||||||||||||||||||||||||||||||||||||
#define _CORE_TIMER_VECTOR 0 #define _EXTERNAL_0_VECTOR 3 #define _UART6_RX_VECTOR 189 #define _ADC7_WARM_VECTOR 213 #include <stdio.h> typedef enum { APP_STATE_INIT=0, APP_STATE_DISK_SCANNING, APP_STATE_OPEN_FILE, APP_STATE_SEND_DATA, } APP_STATES; //アプリケーションの状態を示す列挙型APP_STATESを定義 typedef enum { COLOR_Red = 0xf800, COLOR_Blue = 0x001f, COLOR_NavyBlue = 0x0019, COLOR_ForestGreen = 0x1c43, }SYS_COLOR; //色を示す列挙型SYS_COLORを定義 typedef enum { INT_SOURCE_CORE_TIMER = _CORE_TIMER_VECTOR, INT_SOURCE_EXTERNAL_0 = _EXTERNAL_0_VECTOR, INT_SOURCE_UART6_RX = _UART6_RX_VECTOR, INT_SOURCE_ADC7_WARM = _ADC7_WARM_VECTOR, } INT_SOURCE; //割込みベクタ番号の列挙型を定義 typedef struct { APP_STATES state; //アプリケーションの状態の列挙型メンバー変数、 SYS_COLOR color; //色の列挙型メンバー変数 INT_SOURCE source; ////割込みベクタ番号の列挙型メンバー変数 } APP_DATA; //アプリケーションのデータを格納する構造体を定義 int main() { APP_DATA appData; //構造体の変数宣言、オブジェクト生成 appData.state = APP_STATE_OPEN_FILE; //メンバー変数、オブジェクトを初期化 appData.color = COLOR_NavyBlue; appData.source = _UART6_RX_VECTOR; printf("appData.state = %d, APP_STATE = APP_STATE_OPEN_FILE\n",appData.state); printf("appData.color = 0x%04x, SYS_COLOR = COLOR_NavyBlue\n",appData.color); printf("appData.source = %d, INT_SOURCE = _UART6_RX_VECTOR\n",appData.source); return 0; } |
||||||||||||||||||||||||||||||||||||
<実行結果> | ||||||||||||||||||||||||||||||||||||
appData.state = 2, APP_STATE = APP_STATE_OPEN_FILE appData.color = 0x0019, SYS_COLOR = COLOR_NavyBlue appData.source = 189, INT_SOURCE = _UART6_RX_VECTOR |
||||||||||||||||||||||||||||||||||||
■ | uintptr_t | |||||||||||||||||||||||||||||||||||
・ ポインタと同じサイズの符号なし整数。 ・ Cで、ポインター保持に充分な大きさの符号なしの整数型。C99(ISO/IEC 9899:1999)で追加された。(使用例 → URL) |
||||||||||||||||||||||||||||||||||||
■ | 関数ポインタ | |||||||||||||||||||||||||||||||||||
関数ポインタで関数を呼び出す方法
|
||||||||||||||||||||||||||||||||||||
(参考使用例: Harmony sys_time_definitions.h) → URL | ||||||||||||||||||||||||||||||||||||
■ 関数ポインタメモ | ||||||||||||||||||||||||||||||||||||
■ | 関数へのポインタをメンバーにもつ構造体 | |||||||||||||||||||||||||||||||||||
・ C言語では構造体の中に関数をメンバーとしてもつことはできないが、関数ポインタを利用すると 関数へのポインタをメンバー変数をもつ構造体をつくることができる。これを使って、同じ呼び出しで異なる関数の呼び出しができる。 この手法はHarmonyの中でよく用いられている。 | ||||||||||||||||||||||||||||||||||||
//10 interface_struct1.c //同じ呼び出しで異なる関数を呼び出す #include <stdio.h> typedef int (*ADD)(int x,int y); //ADDはintを戻り値とする関数名(ポインタ)であると宣言 typedef int (*MUL)(int x,int y); //MULはintを戻り値とする関数名(ポインタ)であると宣言 typedef struct { ADD add; //関数名ADDの変数addを宣言 MUL mul; //関数名MULの変数mulを宣言 }FUNC_INTERFACE; //関数へのポインタをメンバーとする構造体を宣言 typedef struct { int x; //整数の変数xを宣言 int y; //整数の変数yを宣言 FUNC_INTERFACE func_interface; //関数へのポインタをメンバーとする構造体への変数を宣言 }CALC; //関数へのポインタをメンバー変数にもつ構造体を宣言 int add1(int x, int y) { int ans; ans = x + y + 1; return ans; } int add2(int x, int y) { int ans; ans = x + y + 2; return ans; } int multiply1(int x, int y) { int ans; ans = x * y; return ans; } int multiply2(int x, int y) { int ans; ans = x * y * 2; return ans; } int main() { int value; CALC calc; FUNC_INTERFACE func_interface = //構造体初期化 { .add = (ADD)add1, //関数の実体を引き当て .mul = (MUL)multiply1, //関数の実体を引き当て }; value = (*func_interface.add)(1,2); //加算演算実行 printf("value = %d\n", value); value = (*func_interface.mul)(1,2); //乗算演算実行 printf("value = %d\n", value); calc.x = 3; //CALC構造体のxを初期化 calc.y = 4; //CALC構造体のyを初期化 value = (*func_interface.add)(calc.x,calc.y); printf("value = %d\n", value); value = (*func_interface.mul)(calc.x,calc.y); printf("value = %d\n", value); //関数変更 //同じ呼び出しで異なる関数を呼び出す func_interface.add = (ADD)add2; func_interface.mul = (MUL)multiply2; value = (*func_interface.add)(1,2); printf("\nvalue = %d\n", value); value = (*func_interface.mul)(1,2); printf("value = %d\n", value); calc.x = 3; calc.y = 4; value = (*func_interface.add)(calc.x,calc.y); printf("value = %d\n", value); value = (*func_interface.mul)(calc.x,calc.y); printf("value = %d\n", value); } |
||||||||||||||||||||||||||||||||||||
<実行結果> | ||||||||||||||||||||||||||||||||||||
value = 4 value = 2 value = 8 value = 12 value = 5 value = 4 value = 9 value = 24 |
||||||||||||||||||||||||||||||||||||